package com.artemchep.keyguard.common.service.relays.api.firefoxrelay

import com.artemchep.keyguard.common.io.IO
import com.artemchep.keyguard.common.io.ioEffect
import com.artemchep.keyguard.common.model.GeneratorContext
import com.artemchep.keyguard.common.service.relays.api.EmailRelay
import com.artemchep.keyguard.common.service.relays.api.EmailRelaySchema
import com.artemchep.keyguard.feature.confirmation.ConfirmationRoute
import com.artemchep.keyguard.feature.localization.TextHolder
import com.artemchep.keyguard.res.Res
import com.artemchep.keyguard.res.*
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.request.header
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.http.contentType
import io.ktor.http.isSuccess
import kotlinx.collections.immutable.ImmutableMap
import kotlinx.collections.immutable.persistentMapOf
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonPrimitive
import org.kodein.di.DirectDI
import org.kodein.di.instance

class FirefoxRelayEmailRelay(
    private val httpClient: HttpClient,
) : EmailRelay {
    companion object {
        private const val ENDPOINT = "https://relay.firefox.com/api/v1/relayaddresses/"

        private const val KEY_API_KEY = "apiKey"
        private const val HINT_API_KEY = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    }

    override val type = "FirefoxRelay"

    override val name = "Firefox Relay"

    override val docUrl =
        "https://bitwarden.com/help/generator/#tab-firefox-relay-3Uj911RtQsJD9OAhUuoKrz"

    override val schema = persistentMapOf(
        KEY_API_KEY to EmailRelaySchema(
            title = TextHolder.Res(Res.string.api_key),
            hint = TextHolder.Value(HINT_API_KEY),
            type = ConfirmationRoute.Args.Item.StringItem.Type.Token,
            canBeEmpty = false,
        ),
    )

    constructor(directDI: DirectDI) : this(
        httpClient = directDI.instance(),
    )

    override fun generate(
        context: GeneratorContext,
        config: ImmutableMap<String, String>,
    ): IO<String> = ioEffect {
        val apiKey = requireNotNull(config[KEY_API_KEY]) {
            "API key is required for creating an email alias."
        }
        // https://relay.firefox.com/
        val response = httpClient
            .post(ENDPOINT) {
                header("Authorization", "Token $apiKey")

                val body = FirefoxRelayRequest(
                    enabled = true,
                    description = "Generated by Keyguard.",
                )
                contentType(ContentType.Application.Json)
                setBody(body)
            }
        require(response.status.isSuccess()) {
            // Example of an error:
            // {"detail":"Invalid token."}
            val message = runCatching {
                val result = response
                    .body<JsonObject>()
                result["detail"]?.jsonPrimitive?.content
            }.getOrNull()
            message ?: HttpStatusCode.fromValue(response.status.value).description
        }
        val result = response
            .body<JsonObject>()
        val alias = result["full_address"]?.jsonPrimitive?.content
        requireNotNull(alias) {
            "Email alias is missing from the response. " +
                    "Please report this to the developer."
        }
    }

    @Serializable
    private data class FirefoxRelayRequest(
        val enabled: Boolean,
        val description: String,
    )
}
